package com.baomibing.flow.model;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomibing.core.exception.ServerRuntimeException;
import com.baomibing.flow.constant.*;
import com.baomibing.flow.enginee.Process;
import com.baomibing.flow.enginee.*;
import com.baomibing.flow.exception.FlowExceptionEnum;
import com.baomibing.flow.execute.Execution;
import com.baomibing.flow.express.Expression;
import com.baomibing.flow.json.*;
import com.baomibing.flow.track.NodeHistory;
import com.baomibing.flow.track.ProcessTrack;
import com.baomibing.flow.ui.*;
import com.baomibing.tool.constant.Formats;
import com.baomibing.tool.util.Checker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.EnumUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * WorkFlow
 *
 * @author frog 2023/9/18 14:00
 * @version 1.0.0
 **/
@Slf4j
@Data @ToString
@Accessors(chain = true)
public class WorkFlow {

    private String id;

    private String instanceId;

    private String name;

    private String style;

    private List<NodeHistory> executeOrders = Lists.newArrayList();

    private StartNode start;

    private EndNode end;

    private Boolean beComplete = Boolean.FALSE;

    private List<Process> processes;

    private List<WorkNode> currents = Lists.newCopyOnWriteArrayList();

    private List<ProcessTrack> tracks = Lists.newCopyOnWriteArrayList();

    private UViewPort viewPort;

    //存储流程中所有节点映射
    private Map<String, BaseNode> nodeMap = Maps.newLinkedHashMap();

    private AtomicInteger step = new AtomicInteger(1);

    public void withStep(int value) {
        step.set(value);
    }

    //是否执行了流程，每次执行都会更新
    private Boolean beExecuteProcess = false;
    
    public void addCurrents(List<WorkNode> nodes) {
    	if (Checker.beEmpty(nodes)) {
    		return;
    	}
    	nodes.forEach(n -> currents.add(n));
    }


    public void doStart(Execution execution) {
        if (Checker.beNotEmpty(currents)) {
            throw new ServerRuntimeException(FlowExceptionEnum.FLOW_HAVE_BEEN_STARTED);
        }

        this.currents.add(start);

        Map<String, Execution> executionMap = new HashMap<>();
        executionMap.put(this.start.getName(), execution);
        doExecute(executionMap);
    }


    public void printCurrent() {
        if (Checker.beEmpty(currents)) {
            throw new ServerRuntimeException(FlowExceptionEnum.THERE_IS_NO_EXECUTING_NODE);
        }
        for (WorkNode node : currents) {
            log.info("-----------当前已执行到:{}", node.getName());
        }
    }

    public void doExecute(Map<String, Execution> executionMap ) {
        if (Checker.beEmpty(currents)) {
            throw new ServerRuntimeException(FlowExceptionEnum.THERE_IS_NO_EXECUTING_NODE);
        }
        if (Checker.beEmpty(executionMap)) {
            throw new ServerRuntimeException(FlowExceptionEnum.EXECUTE_PARAMS_EMPTY);
        }
        boolean matchNode = currents.stream().anyMatch(n -> executionMap.containsKey(n.getName()));
        if (!matchNode) {
            throw new ServerRuntimeException(FlowExceptionEnum.CAN_NOT_MATCH_EXECUTING_NODE);
        }
        for (WorkNode node : currents) {

            Execution execution = executionMap.get(node.getName());
            if (Checker.beNull(execution)) {
                continue;
//                throw new RuntimeException("当前的参数无效，无法执行");
            }
            log.info("++++++++当前正在执行:{}", node.getName());
            node.execute(execution);
        }


    }


    public void doExecute(String name, Execution execution) {
        if (Checker.beEmpty(currents)) {
            throw new ServerRuntimeException(FlowExceptionEnum.THERE_IS_NO_EXECUTING_NODE);
        }
        if (Checker.beNull(execution)) {
            throw new ServerRuntimeException(FlowExceptionEnum.EXECUTE_PARAMS_EMPTY);
        }

        boolean matchNode = this.currents.stream().anyMatch((n) -> name.equals(n.getName()));
        if (!matchNode) {
            throw new ServerRuntimeException(FlowExceptionEnum.CAN_NOT_MATCH_EXECUTING_NODE);
        }
        for (WorkNode node : currents) {

            if (!node.getName().equals(name)) continue;
            log.info("++++++++当前正在执行:{}", node.getName());
            node.execute(execution);
        }
        int afterSize = tracks.size();

    }


    public void doExecuteReject(String name, Execution execution) {
        if (Checker.beEmpty(currents)) {
            throw new ServerRuntimeException(FlowExceptionEnum.THERE_IS_NO_EXECUTING_NODE);
        }
        if (Checker.beNull(execution)) {
            throw new ServerRuntimeException(FlowExceptionEnum.EXECUTE_PARAMS_EMPTY);
        }

        boolean matchNode = this.currents.stream().anyMatch((n) -> name.equals(n.getName()));
        if (!matchNode) {
            throw new ServerRuntimeException(FlowExceptionEnum.CAN_NOT_MATCH_REJECTING_NODE);
        }
        for (WorkNode current : currents) {
            if (!current.getName().equals(name)) continue;
            log.info("++++++++当前正在驳回:{}", current.getName());
            current.reject(execution);
        }


    }

    public void doExecuteReject(Map<String,Execution> executionMap) {
        if (Checker.beEmpty(currents)) {
            throw new ServerRuntimeException(FlowExceptionEnum.THERE_IS_NO_EXECUTING_NODE);
        }
        if (Checker.beNull(executionMap)) {
            throw new ServerRuntimeException(FlowExceptionEnum.EXECUTE_PARAMS_EMPTY);
        }
        boolean matchNode = currents.stream().anyMatch(n -> executionMap.containsKey(n.getName()));
        if (!matchNode) {
            throw new ServerRuntimeException(FlowExceptionEnum.CAN_NOT_MATCH_REJECTING_NODE);
        }
        for (WorkNode current : currents) {
            Execution execution = executionMap.get(current.getName());
            if (Checker.beNull(execution)) {
                continue;
            }
            log.info("++++++++当前正在驳回:{}", current.getName());
            current.reject(execution);
        }

    }

    public void removeIfExist(WorkNode old) {
        currents.removeIf(current -> current.getName().equals(old.name));
    }

    public void updateWorkNode(WorkNode old, WorkNode news) {
        if (Checker.beEmpty(currents)) {
            currents = Lists.newCopyOnWriteArrayList();
        }

        removeIfExist(old);

        boolean match = currents.stream().anyMatch(n -> n.getName().equals(news.name));
        if (!match) {
            if (news instanceof EndNode) {
                setBeComplete(Boolean.TRUE);
            } else {
                setBeComplete(Boolean.FALSE);
            }
            currents.add(news);
        }
    }

    private ProcessTrack findTrackNode(WorkNode node) {
        for (ProcessTrack t : tracks) {
            if (node.name.equals(t.getNode().name)) {
                return t;
            }
        }
        return null;
    }


    private ProcessTrack findTrackSourceOfNode(List<WorkNode> sources) {
        List<ProcessTrack> list = Lists.newArrayList();
        for (ProcessTrack t : tracks) {
            for (WorkNode source: sources) {
                if (t.getNode().name.equals(source.name)) {
                    return t;
                }
            }
        }
        return null;
    }

    private ProcessTrack findTrackTargetOfNode(WorkNode node) {
        List<ProcessTrack> list = Lists.newArrayList();
        for (ProcessTrack t : tracks) {
            for (WorkNode target: t.getTargets()) {
                if (node.name.equals(target.name)) {
                    return t;
                }
            }
        }

        return null;
    }

    public void ordering() {
        Ordering<ProcessTrack> ordering = new Ordering<ProcessTrack>() {
            @Override
            public int compare(@Nullable ProcessTrack left, @Nullable ProcessTrack right) {
                return  right.getLevel() - left.getLevel();
            }
        };
        tracks.sort(ordering);
    }

    public void updateTrack(ProcessTrack track) {
        if (Checker.beNull(tracks)) {
            tracks = Lists.newCopyOnWriteArrayList();
        }

        WorkNode node = track.getNode();
        if (node instanceof StartNode) {
            track.setLevel(0);
        } else {
            ordering();
            ProcessTrack targets = findTrackTargetOfNode(track.getNode());
            int maxLevel = tracks.get(0).getLevel();
            if (maxLevel - targets.getLevel() > 1) {
                targets = findTrackSourceOfNode(track.getSources());
            }
            track.setLevel(targets.getLevel() + 1);
        }

        tracks.add(track);
        if ((track.getNode() instanceof TaskNode)) {
            NodeHistory history = new NodeHistory();
            history.setTask((TaskNode) track.getNode());
            history.setActor(track.getActor()).setDate(track.getExecuteTime()).setExecuteType(track.getExecuteType())
                    .setStep(track.getLevel()).setAction(track.getAction()).setNodeType(track.getNodeType());
            executeOrders.add(history);
        }

        Ordering<NodeHistory> ordering = new Ordering<NodeHistory>() {
            @Override
            public int compare(@Nullable NodeHistory left, @Nullable NodeHistory right) {
                return  right.getStep() - left.getStep();
            }
        };
        executeOrders.sort(ordering);

    }

    public void doOrdering() {
        Map<Integer, Integer> levelMap = Maps.newHashMap();
        for (NodeHistory node : executeOrders) {
            if (Checker.beNull(levelMap.get(node.getStep()))) {
                levelMap.put(node.getStep(), step.getAndIncrement());
            }
            node.setStep(levelMap.get(node.getStep()));
        }

    }

    public void updateExecuteHistory(NodeHistory history) {
        executeOrders.add(history);
//        Map<Integer, List<NodeHistory>> maps = executeOrders.stream().collect(Collectors.groupingBy(NodeHistory::getStep));
////        AtomicInteger step = new AtomicInteger(1);
//        maps.forEach((k,v) -> {
//            v.forEach(h -> h.setStep(step.get()));
//            step.getAndIncrement();
//        });
    }

    private String date2String(Date date) {
        return new DateTime(date).toString(Formats.DEFAULT_DATE_TIME_FORMAT);
    }

    public void printExecutedTasks() {
        for (NodeHistory history : executeOrders) {
            String type = history.getExecuteType() == ProcessExecuteEnum.PROCESS ? "审核" : "驳回";
            log.info("第{}步 {} {} {} {}", history.getStep(), date2String(history.getDate()), history.getActor(), type, history.getTask().name);
        }
    }



    public void printTracks() {
        Map<Integer, List<ProcessTrack>> map = tracks.stream().collect(Collectors.groupingBy(ProcessTrack::getLevel));

        map.forEach((k,v) -> {
            log.info("==LEVEL {} :", k);
            log.info("==================");
            for (ProcessTrack pt : v) {
                String type = pt.getExecuteType() == ProcessExecuteEnum.PROCESS ? "审核" : "驳回";
                for (WorkNode t : pt.getTargets()) {
                    log.info("执行人:{}, 已完成- {}: {} -> {}", pt.getActor(), type, pt.getNode().getName(), t.name);
                }
            }
            log.info("==================");
        });
    }

    private boolean doInternalProcess(List<? extends Process> processes, WorkNode node, TransitionNode action, Execution execution) {
        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (doSubProcessIfMatch(subProcess, node, action, execution)) {
                    return true;
                }

            } else if (process instanceof ParallelProcess) {
                ParallelProcess parallelProcess = (ParallelProcess) process;
                return doInternalProcess(parallelProcess.getProcesses(), node ,action, execution);
            } else if (process instanceof ForkProcess) {
                ForkProcess forkProcess = (ForkProcess) process;
                return doInternalProcess(forkProcess.getProcesses(), node, action, execution);
            } else if (process instanceof JoinProcess) {
                JoinProcess joinProcess = (JoinProcess) process;
                List<SubProcess> subProcesses = joinProcess.getProcesses();
                return doInternalProcess(subProcesses, node, action, execution);
            }
        }

        return false;
    }

    private boolean doInternalReject(List<? extends Process> processes, WorkNode node, TransitionNode action, Execution execution) {
        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (doSubRejectIfMatch(subProcess, node, action, execution)) {
                    return true;
                }

            } else if (process instanceof ParallelProcess) {
                ParallelProcess parallelProcess = (ParallelProcess) process;
                return doInternalReject(parallelProcess.getProcesses(), node ,action, execution);
            } else if (process instanceof ForkProcess) {
                ForkProcess forkProcess = (ForkProcess) process;
                return doInternalReject(forkProcess.getProcesses(), node, action, execution);
            } else if (process instanceof JoinProcess) {
                JoinProcess joinProcess = (JoinProcess) process;
                if (doInternalReject(Lists.newArrayList(joinProcess.getTargetProcess()), node, action, execution)) {
                    return joinProcess.doReject(execution);
                }
            }
        }

        return false;
    }

    private void doInternalVirtualReject(List<? extends Process> processes, WorkNode node, TransitionNode action) {
        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                doSubVirtualRejectIfMatch(subProcess, node, action);
            } else if (process instanceof ParallelProcess) {
                ParallelProcess parallelProcess = (ParallelProcess) process;
                doInternalVirtualReject(parallelProcess.getProcesses(), node ,action);
            } else if (process instanceof ForkProcess) {
                ForkProcess forkProcess = (ForkProcess) process;
                doInternalVirtualReject(forkProcess.getProcesses(), node, action);
            } else if (process instanceof JoinProcess) {
                JoinProcess joinProcess = (JoinProcess) process;
                doInternalVirtualReject(Lists.newArrayList(joinProcess.getTargetProcess()), node, action);
                doInternalVirtualReject(joinProcess.getProcesses(), node ,action);

            }
        }


    }

    private boolean doSubProcessIfMatch(SubProcess subProcess, WorkNode node, TransitionNode action, Execution execution) {
        boolean beMatch = node.getName().equals(subProcess.getSource().getName()) && action.getName().equals(subProcess.getAction().getName());
        if (beMatch) {
            if (!subProcess.doProcess(execution)) {
                throw new ServerRuntimeException(FlowExceptionEnum.EXECUTE_SUB_PROCESS_FAILURE);
            }
            return true;
        }
        return false;
    }

    private boolean doSubRejectIfMatch(SubProcess subProcess, WorkNode node, TransitionNode action, Execution execution) {
        boolean beMatch = node.getName().equals(subProcess.getTarget().getName()) && action.getName().equals(subProcess.getAction().getName());
        if (beMatch) {
            if (!subProcess.doReject(execution)) {
                throw new ServerRuntimeException(FlowExceptionEnum.EXECUTE_SUB_PROCESS_FAILURE);
            }
            return true;
        }
        return false;
    }

    private void doSubVirtualRejectIfMatch(SubProcess subProcess, WorkNode node, TransitionNode action) {
        boolean beMatch = node.getName().equals(subProcess.getTarget().getName()) && action.getName().equals(subProcess.getAction().getName());
        if (beMatch) {
            subProcess.doVirtualReject();
        }
    }

    public  boolean doProcess(WorkNode node, TransitionNode action, Execution execution) {
        if (Checker.beNull(node)) {
            throw new ServerRuntimeException(FlowExceptionEnum.WORK_NODE_NOT_BE_NULL);
        }
        if (Checker.beNull(action)) {
            throw new ServerRuntimeException(FlowExceptionEnum.ACTION_NOT_BE_NULL);
        }



        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (doSubProcessIfMatch(subProcess, node ,action, execution)) {
                    return true;
                }

            }
            else  {
                if (doInternalProcess(Lists.newArrayList(process), node ,action, execution)) {
                    return true;
                }

            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_SUB_PROCESS_OF_NODE_AND_ACTION, node.getName(), action.getName());
    }

    public boolean doReject(WorkNode node, TransitionNode action, Execution execution) {
        if (Checker.beNull(node)) {
            throw new ServerRuntimeException(FlowExceptionEnum.WORK_NODE_NOT_BE_NULL);
        }
        if (Checker.beNull(action)) {
            throw new ServerRuntimeException(FlowExceptionEnum.ACTION_NOT_BE_NULL);
        }

        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (doSubRejectIfMatch(subProcess, node ,action, execution)) {
                    return true;
                }

            }
            else  {
                if (doInternalReject(Lists.newArrayList(process), node ,action, execution)) {
                    return true;
                }

            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_SUB_PROCESS_OF_NODE_AND_ACTION, node.getName(), action.getName());

    }

    public void doVirtualReject(WorkNode node, TransitionNode action) {
        if (Checker.beNull(node)) {
            throw new ServerRuntimeException(FlowExceptionEnum.WORK_NODE_NOT_BE_NULL);
        }
        if (Checker.beNull(action)) {
            throw new ServerRuntimeException(FlowExceptionEnum.ACTION_NOT_BE_NULL);
        }

        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                doSubVirtualRejectIfMatch(subProcess, node ,action);
            }
            else  {
               doInternalVirtualReject(Lists.newArrayList(process), node ,action);

            }
        }

    }

    //将目标节点和起始节点中间的所有流程都设置为未完成
    public void doProcessNotComplete(WorkNode source, WorkNode target) {
        target.getInputs().forEach(line -> {
            WorkNode lineSource = line.rejectVirtual();
            if (lineSource.getName().equals(source.getName()) || start.getName().equals(lineSource.getName())) {
                return;
            }
            doProcessNotComplete(source, lineSource);
        });
    }

    //添加一条直达发起人节点的路径
    public SubProcess fillSubProcess2FillNode(WorkNode node, RecommitPolicyEnum policy) {
        BaseNode workNode = nodeMap.values().stream().filter(n -> NodeTypeEnum.Task.name().equals(n.getNodeType()) && TaskModelEnum.FILL.equals(((TaskNode)n).getModel())).findFirst().orElse(null);
        if (Checker.beNull(workNode)) {
            throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_FILL_NODE);
        }
        TaskNode taskNode = (TaskNode)workNode;
        taskNode.setRecommitPolicy(policy);
        //驳回后重新审核策略为 提交到上次驳回的位置 设置对应位置节点名称
        if (RecommitPolicyEnum.COMMIT_TO_LATEST_REJECT == policy) {
            taskNode.setDirectToTarget(node.getName());
        } else if (RecommitPolicyEnum.COMMIT_NEXT_STEP == policy) {
            doProcessNotComplete(taskNode, node);
        }
        TransitionNode action = new TransitionNode(taskNode, node);
        SubProcess subProcess = new SubProcess(this).source(taskNode).target(node).action(action);
        processes.add(subProcess);
        return subProcess;
    }

    public SubProcess fillSubProcess2DirectNode(WorkNode node, String name) {
        BaseNode workNode = nodeMap.values().stream().filter(n -> n.getName().equals(name)).findFirst().orElse(null);
        if (Checker.beNull(workNode)) {
            throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_DIRECT_TARGET_NODE);
        }
        TaskNode taskNode = (TaskNode)workNode;
        TransitionNode action = new TransitionNode(node, taskNode);
        SubProcess subProcess = new SubProcess(this).source(node).target(taskNode).action(action);
        processes.add(subProcess);
        return subProcess;
    }

    //删除路径
    public void deleteSubProcess(SubProcess sub) {
        Iterator<Process> it = processes.iterator();
        while (it.hasNext()) {
            Process p = it.next();
            if (p instanceof SubProcess) {
                SubProcess sp = (SubProcess) p;
                if (sp.getSource().equals(sub.getSource()) && sp.getTarget().equals(sub.getTarget())) {
                    it.remove();
                    return;
                }
            }
        }
    }


    public boolean doForkProcess(WorkNode node, Execution execution) {
        for (Process process : processes) {
            if (process instanceof ForkProcess) {
                ForkProcess forkProcess = (ForkProcess) process;
                if (node.getName().equals(forkProcess.getNode().getName())) {
                    return forkProcess.doProcess(execution);
                }
            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_NODE_OF_FORK_PROCESS);
    }
    public boolean doForkReject(WorkNode node, Execution execution) {
        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (node.getName().equals(subProcess.getTarget().getName())) {
                    if (subProcess.getSource() instanceof TaskNode) {
                        TaskNode tn = (TaskNode) subProcess.getSource();
                        tn.doChildReject(execution);
                    }
                    return subProcess.doReject(execution);
                }
            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_NODE_OF_FORK_PROCESS);
    }

    public void doForkVirtualReject(WorkNode node) {
        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (node.getName().equals(subProcess.getTarget().getName())) {
                    if (subProcess.getSource() instanceof TaskNode) {
                        TaskNode tn = (TaskNode) subProcess.getSource();
                        tn.doChildVirtualReject();
                    }

                    subProcess.doVirtualReject();
                }
            }
        }
    }

    public boolean doParallelProcess(WorkNode node, Execution execution) {
        for (Process process : processes) {
            if (process instanceof ParallelProcess) {
                ParallelProcess parallelProcess = (ParallelProcess) process;
                if (parallelProcess.getSource().getName().equals(node.name)) {
                    return parallelProcess.doProcess(execution);
                }
            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_NODE_OF_PARALLEL_PROCESS);
    }

    public boolean doParallelReject(WorkNode node, Execution execution) {
        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (node.getName().equals(subProcess.getTarget().getName())) {
                    if (subProcess.getSource() instanceof TaskNode) {
                        TaskNode tn = (TaskNode) subProcess.getSource();
                        tn.doChildReject(execution);
                    }

                    return subProcess.doReject(execution);
                }
            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_NODE_OF_PARALLEL_PROCESS);
    }

    public void doParallelVirtualReject(WorkNode node) {
        for (Process process : processes) {
            if (process instanceof SubProcess) {
                SubProcess subProcess = (SubProcess) process;
                if (node.getName().equals(subProcess.getTarget().getName())) {
                    if (subProcess.getSource() instanceof TaskNode) {
                        TaskNode tn = (TaskNode) subProcess.getSource();
                        tn.doChildVirtualReject();
                    }
                    subProcess.doVirtualReject();
                }
            }
        }
    }

    public boolean doJoinProcess(WorkNode node, Execution execution) {
        for (Process process : processes) {
            if (process instanceof JoinProcess) {
                JoinProcess joinProcess = (JoinProcess) process;
                if (joinProcess.matchSource(node)) {
                    return joinProcess.doProcess(execution);
                }
            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_NODE_OF_JOIN_PROCESS);
    }

    public boolean doJoinReject(WorkNode node, Execution execution) {
        for (Process process : processes) {
            if (process instanceof JoinProcess) {
                JoinProcess joinProcess = (JoinProcess) process;
                if (joinProcess.matchSource(node)) {
                    return joinProcess.doReject(execution);
                }
            }
        }
        throw new ServerRuntimeException(FlowExceptionEnum.NOT_FOUND_THE_NODE_OF_JOIN_PROCESS);
    }

    public void doJoinVirtualReject(WorkNode node) {
        for (Process process : processes) {
            if (process instanceof JoinProcess) {
                JoinProcess joinProcess = (JoinProcess) process;
                if (joinProcess.matchSource(node)) {
                    joinProcess.doVirtualReject();
                }
            }
        }
    }

    private void assign(JBase base, BaseNode node) {
        if (node instanceof WorkNode) {
            WorkNode workNode = (WorkNode) node;
            base.setIcon(workNode.getIcon()).setPosition(JSON.toJSONString(workNode.getPosition()))
                    .setMeasured(JSON.toJSONString(workNode.getMeasured()))
                    .setLpaths(JSONArray.toJSONString(workNode.getLpaths()))
                    .setRpaths(JSONArray.toJSONString(workNode.getRpaths()))
                    .setVariables(JSONArray.toJSONString(workNode.getVariables()))
                    .setDeleteable(workNode.getDeleteable()).setSelected(workNode.getSelected())
                    .setDragging(workNode.getDragging()).setPassed(workNode.getPassed());
        }
    }

    private JBase serialWorkNode(Map<String, JBase> map, BaseNode node) {
        NodeTypeEnum nt = EnumUtils.getEnum(NodeTypeEnum.class, node.nodeType);
        JBase jbase;
        switch (nt) {
            case Start:
                jbase = new JStart().setName(node.name).setNodeId(node.getNodeId());
                assign(jbase, node);
                break;
            case End:
                jbase = new JEnd().setName(node.name).setNodeId(node.getNodeId());
                assign(jbase, node);
                break;
            case Fork:
                ForkNode forkNode = (ForkNode) node;
                jbase = new JFork().setModel(forkNode.getModel().name()).setName(node.name).setNodeId(node.getNodeId()) ;
                assign(jbase, node);
                break;
            case Join:
                JoinNode joinNode = (JoinNode) node;
                jbase = new JJoin().setExeType(joinNode.getExeType().name()).setName(node.name).setNodeId(node.getNodeId());
                assign(jbase, node);
                break;
            case Parallel:
                ParallelNode parallelNode = (ParallelNode) node;
                jbase = new JParallel().setModel(parallelNode.getModel().name()).setExeType(parallelNode.getExeType().name())
                        .setName(node.name).setNodeId(node.getNodeId());
                assign(jbase, node);
                break;
            case Transit:
                TransitionNode transition = (TransitionNode) node;
                jbase = new JTransition().setExpression(Checker.beNotNull(transition.getExpression()) ? transition.getExpression().getExpress() : null)
                        .setParams(transition.getParams())
                        .setSource(transition.getSource().getName()).setTarget(transition.getTarget().getName())
                        .setSourceHandle(transition.getSourceHandle()).setTargetHandle(transition.getTargetHandle())
                        .setName(transition.getName()).setNodeId(node.getNodeId()).setPassed(transition.getPassed());
                break;
            case Task:
                TaskNode task = (TaskNode) node;
                jbase = new JTask().setModel(task.getModel().name()).setTaskAdvice(task.getTaskAdvice())
                        .setAllActionRejectType(task.getAllActionRejectType().name())
                        .setDirectToTarget(task.getDirectToTarget())
                        .setRecommitPolicy(task.getRecommitPolicy().name())
                        .setRejectPolicy(task.getRejectPolicy().name())
                        .setTaskType(task.getTaskType().name())
                        .setActionType(task.getActionType().name())
                        .setEntrusts(task.getEntrusts()).setEntrustType(task.getEntrustType().name())
                        .setBeAllActionComplete(task.getBeAllActionComplete()).setBeAllActionReject(task.getBeAllActionReject())
                        .setChildProcess(serialTaskJoinProcess(map, task.getChildProcess())).setName(task.getName())
                        .setNodeId(node.getNodeId());
                assign(jbase, node);
                break;
            default:
                throw new ServerRuntimeException(FlowExceptionEnum.NOT_SUPPORT_THE_TYPE_OF_WORK_NODE, nt.name());

        }
        return jbase;
    }

    private void putIfNotExist(Map<String, JBase> map, BaseNode node) {
        if (map.get(node.getName()) == null) {
            map.put(node.getName(), serialWorkNode(map, node));
        }
    }

    private JSubProcess serialSubProcess(Map<String, JBase> map, SubProcess subProcess) {
        JSubProcess jsub = new JSubProcess();
        WorkNode source = subProcess.getSource();
        WorkNode target = subProcess.getTarget();
        TransitionNode transition = subProcess.getAction();
        putIfNotExist(map, source);
        putIfNotExist(map, target);
        putIfNotExist(map, transition);

        jsub.setSource(source.getName()).setTarget(target.getName()).setAction(transition.getName()).setState(subProcess.getState()).setActor(subProcess.getActor());

        return jsub;
    }

    private JForkProcess serialForkProcess(Map<String, JBase> map, ForkProcess forkProcess) {
        JForkProcess jfork = new JForkProcess();
        ForkNode node = forkProcess.getNode();
        map.put(node.getName(), serialWorkNode(map, node));
        jfork.setProcesses(serialProcess(map, forkProcess.getProcesses())).setNode(node.getName());
        return jfork;
    }

    private JTransition serialChildTransition(TransitionNode transition) {
        JTransition jbase = new JTransition().setExpression(Checker.beNotNull(transition.getExpression()) ? transition.getExpression().getExpress() : null)
                .setParams(transition.getParams()).setBeChild(true)
                .setSourceHandle(transition.getSourceHandle()).setTargetHandle(transition.getTargetHandle())
                .setSource(transition.getSource().getName()).setTarget(transition.getTarget().getName());
        jbase.setName(transition.getName());
        return jbase;
    }


    private JSubProcess serialChildSubProcess(Map<String, JBase> map, SubProcess subProcess) {
        JSubProcess jsub = new JSubProcess();
        WorkNode source = subProcess.getSource();
        WorkNode target = subProcess.getTarget();
        TransitionNode transition = subProcess.getAction();
        if (!transition.getName().contains("_" + subProcess.getActor())) {
            transition.setName(transition.getName() + "_" + subProcess.getActor());
        }
        if (!(source instanceof TaskNode)) {
            putIfNotExist(map, source);
        }
        putIfNotExist(map, target);
        if (Checker.beNull(map.get(transition.getName()))) {
            map.put(transition.getName(), serialChildTransition(transition));
        }

        jsub.setSource(source.getName()).setTarget(target.getName()).setAction(transition.getName()).setState(subProcess.getState()).setActor(subProcess.getActor());

        return jsub;
    }


    private JJoinProcess serialJoinProcess(Map<String, JBase> map, JoinProcess joinProcess) {
        JJoinProcess jjoin = new JJoinProcess();
        JSubProcess jtargetProcess = serialSubProcess(map, joinProcess.getTargetProcess());
        List<JSubProcess> jsubProcesses = Lists.newArrayList();
        List<SubProcess> subProcesses = joinProcess.getProcesses();
        for (int i = subProcesses.size() - 1; i >= 0; i--) {
            jsubProcesses.add(0 , serialSubProcess(map, subProcesses.get(i)));
        }
        jjoin.setProcesses(jsubProcesses).setTargetProcess(jtargetProcess);
        return jjoin;
    }

    private JParallelProcess serialParallelProcess(Map<String, JBase> map, ParallelProcess parallelProcess) {
        JParallelProcess jparallel = new JParallelProcess();
        WorkNode node = parallelProcess.getSource();
        map.put(node.getName(), serialWorkNode(map, node));
        jparallel.setSource(node.getName()).setProcesses(serialProcess(map, parallelProcess.getProcesses()));
        return jparallel;
    }

    private JTaskJoinProcess serialTaskJoinProcess(Map<String, JBase> map, TaskJoinProcess taskJoinProcess) {
        if (taskJoinProcess == null) {
            return null;
        }
        JTaskJoinProcess jtaskJoinProcess = new JTaskJoinProcess();
        List<JSubProcess> jsubProcesses = Lists.newArrayList();
        List<SubProcess> subProcesses = taskJoinProcess.getProcesses();
        for (int i = subProcesses.size() - 1; i >= 0; i--) {
            jsubProcesses.add(0 , serialChildSubProcess(map, subProcesses.get(i)));
        }
        jtaskJoinProcess.setProcesses(jsubProcesses);
        return jtaskJoinProcess;
    }

    private List<JProcess> serialProcess(Map<String, JBase> nodeMap, List<? extends Process> processes) {
        List<JProcess> jprocesses = Lists.newArrayList();
        for (int i = processes.size() - 1; i >= 0; i--) {
            Process p = processes.get(i);
            ProcessTypeEnum pt = EnumUtils.getEnum(ProcessTypeEnum.class, p.getProcessType());
            switch (pt) {
                case SUB:
                    jprocesses.add(0 ,serialSubProcess(nodeMap, (SubProcess) p));
                    break;
                case FORK:
                    jprocesses.add(0, serialForkProcess(nodeMap, (ForkProcess) p));
                    break;
                case JOIN:
                    jprocesses.add(0, serialJoinProcess(nodeMap, (JoinProcess) p));
                    break;
                case PARALLEL:
                    jprocesses.add(0, serialParallelProcess(nodeMap, (ParallelProcess) p));
                    break;
//                case TASK_JOIN:
//                    jprocesses.add(0, serialTaskJoinProcess(nodeMap, (TaskJoinProcess) p));
//                    break;
                default:
                    throw new ServerRuntimeException(FlowExceptionEnum.NOT_SUPPORT_THE_TYPE_OF_PROCESS, pt.name());
            }
        }
        return jprocesses;

    }

    private List<JProcessTrack> serialProcessTrack(Map<String, JBase> nodeMap, List<ProcessTrack> tracks) {
        List<JProcessTrack> list = Lists.newArrayList();

        if (Checker.beEmpty(nodeMap) || Checker.beEmpty(tracks)) {
            return list;
        }
        for (ProcessTrack t : tracks) {
            JProcessTrack jtrack = new JProcessTrack();
            List<String> sources = Lists.newArrayList();
            List<String> targets = Lists.newArrayList();
            for (WorkNode node : t.getSources()) {
                sources.add(node.getName());
            }
            for (WorkNode node : t.getTargets()) {
                targets.add(node.getName());
            }
            jtrack.setSources(sources).setTargets(targets).setAction(t.getAction()).setNodeType(t.getNode().getNodeType())
                    .setActor(t.getActor()).setLevel(t.getLevel()).setNode(t.getNode().getName())
                    .setExecuteType(t.getExecuteType().name()).setExecuteTime(new DateTime(t.getExecuteTime()).toString(Formats.DEFAULT_DATE_TIME_FORMAT));
            list.add(jtrack);
        }
        return list;
    }

    public JWorkFlow serialize() {
        JWorkFlow jflow = new JWorkFlow();
        Map<String, JBase> nodeMap = Maps.newHashMap();
        jflow.setProcesses(serialProcess(nodeMap, processes));
        jflow.setNodeMap(nodeMap);
        jflow.setTracks(serialProcessTrack(nodeMap, tracks));
        if (Checker.beNotNull(viewPort)) {
            jflow.setViewPort(new JViewPort().setX(viewPort.getX().toPlainString()).setY(viewPort.getY().toPlainString()).setZoom(viewPort.getZoom().toPlainString()));
        }
        return jflow;
    }

    private WorkNode key4WorkNode(Map<String, BaseNode> map, String key) {
        return (WorkNode) map.get(key);
    }

    private ForkNode key4ForkNode(Map<String, BaseNode> map, String key) {
        return (ForkNode) map.get(key);
    }

    private TransitionNode key4Transition(Map<String, BaseNode> map, String key) {
        return (TransitionNode) map.get(key);
    }

    private SubProcess deserialJSubProcess(WorkFlow flow, Map<String, BaseNode> map, JSubProcess jSubProcess) {
        SubProcess subProcess = new SubProcess(flow);

        subProcess.source(key4WorkNode(map, jSubProcess.getSource())).target(key4WorkNode(map, jSubProcess.getTarget()))
                .actor(jSubProcess.getActor()).setState(jSubProcess.getState());
        TransitionNode transition = key4Transition(map, jSubProcess.getAction());
        subProcess.action(transition);
        return subProcess;
    }

    private ForkProcess deserialJForkProcess(WorkFlow flow, Map<String, BaseNode> map, JSONObject jForkProcess) {
        final String PROCESSES = "processes";
        final String NODE = "node";
        ForkProcess forkProcess = new ForkProcess(flow, key4ForkNode(map, jForkProcess.getString(NODE)));
        forkProcess.setProcesses(deserialProcess(flow, map, jForkProcess.getJSONArray(PROCESSES)));
        return forkProcess;
    }

    private JoinProcess deserialJJoinProcess(WorkFlow flow, Map<String, BaseNode> map, JSONObject jJoinProcess) {
        final String TARGET_PROCESS = "targetProcess";
        final String PROCESSES = "processes";
        JoinProcess joinProcess = new JoinProcess(flow);
        joinProcess.setTargetProcess(deserialJSubProcess(flow, map, jJoinProcess.getJSONObject(TARGET_PROCESS).toJavaObject(JSubProcess.class)));
        List<SubProcess> subProcesses = Lists.newArrayList();
        for (JSubProcess jsub : jJoinProcess.getJSONArray(PROCESSES).toJavaList(JSubProcess.class)) {
            subProcesses.add(deserialJSubProcess(flow, map, jsub));
        }
        joinProcess.setProcesses(subProcesses);
        return joinProcess;
    }

    private ParallelProcess deserialJParallelProcess(WorkFlow flow, Map<String, BaseNode> map, JSONObject jParallelProcess) {
        final String PROCESSES = "processes";
        final String SOURCE = "source";
        ParallelProcess parallelProcess = new ParallelProcess(flow);
        parallelProcess.setProcesses(deserialProcess(flow, map, jParallelProcess.getJSONArray(PROCESSES)));
        parallelProcess.source(key4WorkNode(map, jParallelProcess.getString(SOURCE)));
        return parallelProcess;
    }

    private TaskJoinProcess deserialJTaskJoinProcess(WorkFlow flow, Map<String, BaseNode> map, JTaskJoinProcess jTaskJoinProcess) {
        if (jTaskJoinProcess == null) {
            return null;
        }
        TaskJoinProcess taskJoinProcess = new TaskJoinProcess(flow);
        List<SubProcess> subProcesses = Lists.newArrayList();
        for (JSubProcess jsub : jTaskJoinProcess.getProcesses()) {
            subProcesses.add(deserialJSubProcess(flow, map, jsub));
        }
        taskJoinProcess.setProcesses(subProcesses);
        return taskJoinProcess;
    }

    private List<Process> deserialProcess(WorkFlow flow, Map<String, BaseNode> map, JSONArray processArray) {
        final String PROCESS_TYPE = "processType";
        List<Process> processList = Lists.newArrayList();
        for (int i = 0, len = processArray.size(); i < len; i++) {
            JSONObject p = processArray.getJSONObject(i);
            ProcessTypeEnum pt = EnumUtils.getEnum(ProcessTypeEnum.class, p.getString(PROCESS_TYPE));
            switch (pt) {
                case SUB:
                    processList.add(deserialJSubProcess(flow, map, p.toJavaObject(JSubProcess.class)));
                    break;
                case FORK:
                    processList.add(deserialJForkProcess(flow, map, p));
                    break;
                case JOIN:
                    processList.add(deserialJJoinProcess(flow, map, p));
                    break;
                case PARALLEL:
                    processList.add(deserialJParallelProcess(flow, map, p));
                    break;
                default:
                    throw new ServerRuntimeException(FlowExceptionEnum.NOT_SUPPORT_THE_TYPE_OF_PROCESS, pt.name());
            }
        }
        return processList;
    }

    private void deassign(WorkNode workNode, JBase node) {
        workNode.setIcon(node.getIcon()).setPosition(JSON.parseObject(node.getPosition(), UPosition.class))
                .setMeasured(JSON.parseObject(node.getMeasured(), UMeasured.class))
                .setLpaths(JSONArray.parseArray(node.getLpaths(), UPath.class))
                .setRpaths(JSONArray.parseArray(node.getRpaths(), UPath.class))
                .setVariables(JSONArray.parseArray(node.getVariables(), UVariable.class))
                .setDeleteable(node.getDeleteable()).setSelected(node.getSelected())
                .setDragging(node.getDragging()).setPassed(node.getPassed());
    }

    public Map<String, BaseNode> deserialMap(String mapstring) {
        final String NODE_TYPE = "nodeType";
        final String NAME = "name";
        JSONObject jsonObject = JSONObject.parseObject(mapstring);
        Set<String> keySet = jsonObject.keySet();

        Map<String, BaseNode> nodeMap = Maps.newHashMap();

        Map<String, JSONObject> transitMap = Maps.newHashMap();
        Map<String, JSONObject> taskMap = Maps.newHashMap();
        for (String key : keySet) {
            BaseNode node = null;
            JSONObject valueJson = jsonObject.getJSONObject(key);
            NodeTypeEnum nt = EnumUtils.getEnum(NodeTypeEnum.class,valueJson.getString(NODE_TYPE));
            switch (nt) {
                case Start:
                    JStart start = valueJson.toJavaObject(JStart.class);
                    node = new StartNode(start.getName()).setNodeId(start.getNodeId()).setStyle(start.getStyle());
                    deassign((StartNode)node, start);
                    break;
                case End:
                    JEnd end = valueJson.toJavaObject(JEnd.class);
                    node = new EndNode(end.getName()).setNodeId(end.getNodeId()).setStyle(end.getStyle());
                    deassign((EndNode)node, end);
                    break;
                case Fork:
                    JFork fork = valueJson.toJavaObject(JFork.class);
                    node = new ForkNode(fork.getName()).setModel(EnumUtils.getEnum(ForkModelEnum.class, valueJson.getString("model")));
                    node.setNodeId(fork.getNodeId()).setStyle(fork.getStyle());
                    deassign((ForkNode)node, fork);
                    break;
                case Join:
                    JJoin join = valueJson.toJavaObject(JJoin.class);
                    node = new JoinNode(join.getName()).setExeType(EnumUtils.getEnum(JoinExeTypeEnum.class, valueJson.getString("exeType")));
                    node.setNodeId(join.getNodeId()).setStyle(join.getStyle());
                    deassign((JoinNode)node, join);
                    break;
                case Parallel:
                    JParallel parallel = valueJson.toJavaObject(JParallel.class);
                    node = new ParallelNode(parallel.getName())
                            .setModel(EnumUtils.getEnum(ParallelModelEnum.class, valueJson.getString("model")))
                            .setExeType(EnumUtils.getEnum(ParallelExeTypeEnum.class, valueJson.getString("exeType")));
                    node.setNodeId(parallel.getNodeId()).setStyle(parallel.getStyle());
                    deassign((ParallelNode)node, parallel);
                    break;
                case Task:
                    JTask jtask = valueJson.toJavaObject(JTask.class);
                    node = new TaskNode().setTaskType(EnumUtils.getEnum(TaskTypeEnum.class, jtask.getTaskType()))
                            .setAllActionRejectType(EnumUtils.getEnum(AllActionRejectTypeEnum.class, jtask.getAllActionRejectType()))
                            .setDirectToTarget(jtask.getDirectToTarget())
                            .setRecommitPolicy(EnumUtils.getEnum(RecommitPolicyEnum.class, jtask.getRecommitPolicy()))
                            .setRejectPolicy(EnumUtils.getEnum(RejectPolicyEnum.class, jtask.getRejectPolicy()))
                            .setModel(EnumUtils.getEnum(TaskModelEnum.class, jtask.getModel()))
                            .setEntrustType(EnumUtils.getEnum(EntrustTypeEnum.class, jtask.getEntrustType()))
                            .setActionType(EnumUtils.getEnum(ActionTypeEnum.class, jtask.getActionType()))
                            .setBeAllActionComplete(jtask.getBeAllActionComplete()).setBeAllActionReject(jtask.getBeAllActionReject())
                            .withEntrusts(jtask.getEntrusts()).setDescription(jtask.getDescription());
                    node.setNodeId(jtask.getNodeId()).setName(jtask.getName()).setStyle(jtask.getStyle());
                    deassign((TaskNode)node, jtask);
                    if (Checker.beNotNull(jtask.getChildProcess())) {
                        taskMap.put(key, valueJson);
                    }
                    break;
                case Transit:
                    //parse in the next step.
                    transitMap.put(key, valueJson);
                    break;
                default:
                    throw new ServerRuntimeException(FlowExceptionEnum.NOT_SUPPORT_THE_TYPE_OF_WORK_NODE, nt.name());
            }
            if (node != null) {
                nodeMap.put(key, node);
            }

        }

        for (Map.Entry<String, JSONObject> entry : transitMap.entrySet()) {
            String key = entry.getKey();
            JSONObject value = entry.getValue();
            JTransition jTransition = value.toJavaObject(JTransition.class);
            TransitionNode transitionNode;
            if (jTransition.getBeChild()) {
                transitionNode = new TransitionNode(key4WorkNode(nodeMap, jTransition.getSource()), key4WorkNode(nodeMap, jTransition.getTarget()), false, false);
            } else {
                transitionNode = new TransitionNode(key4WorkNode(nodeMap, jTransition.getSource()), key4WorkNode(nodeMap, jTransition.getTarget()));
            }
            transitionNode.setParams(jTransition.getParams()).setExpression(Checker.beNotEmpty(jTransition.getExpression()) ? new Expression(jTransition.getExpression()) : null).setName(jTransition.getName())
                    .setStyle(jTransition.getStyle()).setPassed(jTransition.getPassed());
            transitionNode.setNodeId(jTransition.getNodeId());
            transitionNode.setSourceHandle(jTransition.getSourceHandle());
            transitionNode.setTargetHandle(jTransition.getTargetHandle());
            nodeMap.put(key, transitionNode);
        }

        for (Map.Entry<String, JSONObject> entry : taskMap.entrySet()) {
            String key = entry.getKey();
            JSONObject value = entry.getValue();
            JTask jtask = value.toJavaObject(JTask.class);
            TaskNode task = (TaskNode) key4WorkNode(nodeMap, key);
            task.setChildProcess(deserialJTaskJoinProcess(this, nodeMap, jtask.getChildProcess()));
        }


        return nodeMap;
    }

    public List<Process> deserialize(Map<String, BaseNode> nodeMap, String processString) {
        JSONArray jprocesses = JSONArray.parseArray(processString);
        return deserialProcess(this, nodeMap, jprocesses);
    }

    public List<ProcessTrack> deserialTrack(Map<String, BaseNode> nodeMap, String trackString) {

        final String SOURCES = "sources";
        final String TARGETS = "targets";
        final String NAME = "name";
        final String ACTION = "action";
        final String NODE = "node";
        final String ACTOR = "actor";
        final String EXECUTE_TYPE = "executeType";
        final String LEVEL = "level";
        final String EXECUTE_TIME = "executeTime";
        final String NODE_TYPE = "nodeType";
        JSONArray jtracks = JSONArray.parseArray(trackString);
        List<ProcessTrack> tracks = Lists.newArrayList();
        for (int i = 0, len = jtracks.size(); i < len; i++) {
            ProcessTrack track = new ProcessTrack();
            JSONObject jtrack = jtracks.getJSONObject(i);

            List<String> jsources = JSONArray.parseArray(jtrack.getString(SOURCES), String.class);
            List<WorkNode> sources = Lists.newArrayList();
            for (String s : jsources) {
                sources.add(key4WorkNode(nodeMap, s));
            }

            List<String> jtargets = JSONArray.parseArray(jtrack.getString(TARGETS), String.class);
            List<WorkNode> targets = Lists.newArrayList();
            for (String s : jtargets) {
                targets.add(key4WorkNode(nodeMap, s));
            }
            track.setAction(jtrack.getString(ACTION)).setNodeType(jtrack.getString("NODE_TYPE"))
                    .setNode(key4WorkNode(nodeMap, jtrack.getString(NODE)))
                    .setSources(sources).setTargets(targets).setActor(jtrack.getString(ACTOR))
                    .setLevel(jtrack.getIntValue(LEVEL))
                    .setExecuteType(EnumUtils.getEnum(ProcessExecuteEnum.class, jtrack.getString(EXECUTE_TYPE)))
                    .setExecuteTime(DateTime.parse(jtrack.getString(EXECUTE_TIME), DateTimeFormat.forPattern(Formats.DEFAULT_DATE_TIME_FORMAT)).toDate());
            tracks.add(track);
        }
        return tracks;

    }

    //测试非审批节点(FORK)自动执行
//    public static void main(String[] args) {
//        WorkFlow wf = new WorkFlow();
//        StartNode start = new StartNode("start");
//        TaskNode task = new TaskNode("报销");
//        task.withEntrusts(Lists.newArrayList("ning"));
//        TransitionNode t1 = new TransitionNode(start, task);
//        SubProcess s1 = new SubProcess(wf).source(start).target(task).action(t1);
//
//        ForkNode forkNode = new ForkNode("fork");
//        TransitionNode t2 = new TransitionNode(task, forkNode);
//        SubProcess s2 = new SubProcess(wf).source(task).target(forkNode).action(t2);
//
//
//        TaskNode projector = new TaskNode("项目经理审批").withEntrusts(Lists.newArrayList("han"));
//        TaskNode manger = new TaskNode("部门经理审批").withEntrusts(Lists.newArrayList("wang"));
//        TaskNode director = new TaskNode("总裁审批").withEntrusts(Lists.newArrayList("liu"));
//
//        TransitionNode f1 = new TransitionNode(forkNode, projector).setExpression(new Expression("money <= 100"));
//        SubProcess sf1 = new SubProcess(wf).source(forkNode).target(projector).action(f1);
//
//        TransitionNode f2 = new TransitionNode(forkNode, manger).setExpression(new Expression("money > 100 && money <=1000"));
//        SubProcess sf2 = new SubProcess(wf).source(forkNode).target(manger).action(f2);
//
//        TransitionNode f3 = new TransitionNode(forkNode, director).setExpression(new Expression("money > 1000"));
//        SubProcess sf3 = new SubProcess(wf).source(forkNode).target(director).action(f3);
//        ForkProcess fp = new ForkProcess(wf, forkNode);
//        fp.setProcesses(Lists.newArrayList(sf1, sf2, sf3));
//
//        EndNode end = new EndNode("结束");
//        TransitionNode e1 = new TransitionNode(projector, end);
//        SubProcess se1 = new SubProcess(wf).source(projector).target(end).action(e1);
//
//        TransitionNode e2 = new TransitionNode(manger, end);
//        SubProcess se2 = new SubProcess(wf).source(manger).target(end).action(e2);
//
//        TransitionNode e3 = new TransitionNode(director, end);
//        SubProcess se3 = new SubProcess(wf).source(director).target(end).action(e3);
//
//        List<Process> processList = Lists.newArrayList(s1, s2, fp, se1, se2, se3);
//        wf.setProcesses(processList);
//        wf.setStart(start);
//
//        wf.doStart(Execution.createByNode(start).setActor("ning"));
//        wf.printCurrent();
//
//        Map<String, Execution> map1 = new HashMap<>();
//        Map<String, Object> variables = new HashMap<>();
//        variables.put("money", 1500);
//        map1.put("报销", Execution.createByNode(task).setActor("ning").setVariables(variables));
//        wf.doExecute(map1);
//        wf.printCurrent();
//
////        Map<String, Execution> map2 = new HashMap<>();
////        Map<String, Object> variables = new HashMap<>();
////        variables.put("money", 1500);
////        map2.put("fork", Execution.createByNode(task).setActor("ning").setVariables(variables));
////        wf.doExecute(map2);
////        wf.printCurrent();
////
//        Map<String, Execution> map3 = new HashMap<>();
//        map3.put("总裁审批", Execution.createByNode(task).setActor("liu"));
//        wf.doExecute(map3);
//        wf.printCurrent();
////
//        wf.doExecuteReject(end.name, Execution.createByNode(end).setActor("liu"));
//        wf.printCurrent();
//        wf.doExecuteReject(director.name, Execution.createByNode(director).setActor("liu"));
//        wf.printCurrent();
////
////        Map<String, Execution> map22 = new HashMap<>();
////        Map<String, Object> variables2 = new HashMap<>();
////        variables2.put("money", 1500);
////        map22.put("fork", Execution.createByNode(task).setActor("ning").setVariables(variables2));
////        wf.doExecute(map22);
////        wf.printCurrent();
////
////        wf.doExecuteReject(director.name, Execution.createByNode(director).setActor("liu"));
////        wf.printCurrent();
////
////        wf.doExecuteReject(forkNode.name, Execution.createByNode(forkNode).setActor("ning"));
////        wf.printCurrent();
////
////        wf.doExecuteReject(task.name, Execution.createByNode(task).setActor("ning"));
////        wf.printCurrent();
////
////        wf.doExecuteReject(start.name, Execution.createByNode(start).setActor("ning"));
////        wf.printCurrent();
//
//
//    }



    //报销流程
//    public static void main(String[] args) {
//        WorkFlow wf = new WorkFlow();
//        StartNode start = new StartNode("start");
//        TaskNode task = new TaskNode("报销");
//        task.withEntrusts(Lists.newArrayList("ning"));
//        TransitionNode t1 = new TransitionNode(start, task);
//        SubProcess s1 = new SubProcess(wf).source(start).target(task).action(t1);
//
//        ForkNode forkNode = new ForkNode("fork");
//        TransitionNode t2 = new TransitionNode(task, forkNode);
//        SubProcess s2 = new SubProcess(wf).source(task).target(forkNode).action(t2);
//
//
//        TaskNode projector = new TaskNode("项目经理审批").withEntrusts(Lists.newArrayList("han"));
//        TaskNode manger = new TaskNode("部门经理审批").withEntrusts(Lists.newArrayList("wang"));
//        TaskNode director = new TaskNode("总裁审批").withEntrusts(Lists.newArrayList("liu"));
//
//        TransitionNode f1 = new TransitionNode(forkNode, projector).setExpression(new Expression("money <= 100"));
//        SubProcess sf1 = new SubProcess(wf).source(forkNode).target(projector).action(f1);
//
//        TransitionNode f2 = new TransitionNode(forkNode, manger).setExpression(new Expression("money > 100 && money <=1000"));
//        SubProcess sf2 = new SubProcess(wf).source(forkNode).target(manger).action(f2);
//
//        TransitionNode f3 = new TransitionNode(forkNode, director).setExpression(new Expression("money > 1000"));
//        SubProcess sf3 = new SubProcess(wf).source(forkNode).target(director).action(f3);
//        ForkProcess fp = new ForkProcess(wf, forkNode);
//        fp.setProcesses(Lists.newArrayList(sf1, sf2, sf3));
//
//        EndNode end = new EndNode("结束");
//        TransitionNode e1 = new TransitionNode(projector, end);
//        SubProcess se1 = new SubProcess(wf).source(projector).target(end).action(e1);
//
//        TransitionNode e2 = new TransitionNode(manger, end);
//        SubProcess se2 = new SubProcess(wf).source(manger).target(end).action(e2);
//
//        TransitionNode e3 = new TransitionNode(director, end);
//        SubProcess se3 = new SubProcess(wf).source(director).target(end).action(e3);
//
//        List<Process> processList = Lists.newArrayList(s1, s2, fp, se1, se2, se3);
//        wf.setProcesses(processList);
//        wf.setStart(start);
//
//        wf.doStart(Execution.createByNode(start).setActor("ning"));
//        wf.printCurrent();
//
//        Map<String, Execution> map1 = new HashMap<>();
//        map1.put("报销", Execution.createByNode(task).setActor("ning"));
//        wf.doExecute(map1);
//        wf.printCurrent();
//
//        Map<String, Execution> map2 = new HashMap<>();
//        Map<String, Object> variables = new HashMap<>();
//        variables.put("money", 1500);
//        map2.put("fork", Execution.createByNode(task).setActor("ning").setVariables(variables));
//        wf.doExecute(map2);
//        wf.printCurrent();
//
//        Map<String, Execution> map3 = new HashMap<>();
//        map3.put("总裁审批", Execution.createByNode(task).setActor("liu"));
//        wf.doExecute(map3);
//        wf.printCurrent();
//
//        wf.doExecuteReject(end.name, Execution.createByNode(end).setActor("liu"));
//        wf.printCurrent();
//        wf.doExecuteReject(director.name, Execution.createByNode(director).setActor("liu"));
//        wf.printCurrent();
//
//        Map<String, Execution> map22 = new HashMap<>();
//        Map<String, Object> variables2 = new HashMap<>();
//        variables2.put("money", 1500);
//        map22.put("fork", Execution.createByNode(task).setActor("ning").setVariables(variables2));
//        wf.doExecute(map22);
//        wf.printCurrent();
//
//        wf.doExecuteReject(director.name, Execution.createByNode(director).setActor("liu"));
//        wf.printCurrent();
//
//        wf.doExecuteReject(forkNode.name, Execution.createByNode(forkNode).setActor("ning"));
//        wf.printCurrent();
//
//        wf.doExecuteReject(task.name, Execution.createByNode(task).setActor("ning"));
//        wf.printCurrent();
//
//        wf.doExecuteReject(start.name, Execution.createByNode(start).setActor("ning"));
//        wf.printCurrent();
//
//
//    }

    //辞职驳回流程
    public static void main(String[] args) {
    	
    	
    	
        WorkFlow wf = new WorkFlow();
        StartNode start = new StartNode("start");
        TaskNode task = new TaskNode("辞职");
        task.setActionType(ActionTypeEnum.ALL).withEntrusts(Lists.newArrayList("ning","wang","zhang"));
        TransitionNode t1 = new TransitionNode(start, task);

        SubProcess s1 = new SubProcess(wf).source(start).target(task).action(t1);



        ParallelNode pnode = new ParallelNode("并发");

        JoinNode tempJoin = new JoinNode("合并—" + task.getName());
        List<SubProcess> joinTaskProcess = Lists.newArrayList();
        for (String s : task.getEntrusts()) {
            TransitionNode t = new TransitionNode(task, tempJoin, false, false);
            SubProcess sub = new SubProcess(wf).source(task).actor(s).target(tempJoin).action(t);
            joinTaskProcess.add(sub);
        }
        TaskJoinProcess taskJoinProcess = new TaskJoinProcess(wf);
        taskJoinProcess.setProcesses(joinTaskProcess);
         task.setChildProcess(taskJoinProcess);

        TransitionNode t2 = new TransitionNode(task, pnode);
        SubProcess s2 = new SubProcess(wf).source(task).target(pnode).action(t2);


        TaskNode resourceTask = new TaskNode("人力交接");
        resourceTask.withEntrusts(Lists.newArrayList("哈女士"));
        TransitionNode pt2 = new TransitionNode(pnode, resourceTask);
        SubProcess ps2 = new SubProcess(wf).source(pnode).target(resourceTask).action(pt2);


        TaskNode financeTask = new TaskNode("财务交接");
        financeTask.withEntrusts(Lists.newArrayList("王女士"));
        TransitionNode pt3 = new TransitionNode(pnode, financeTask);
        SubProcess ps3 = new SubProcess(wf).source(pnode).target(financeTask).action(pt3);

        TaskNode workTask = new TaskNode("工作交接");
        workTask.withEntrusts(Lists.newArrayList("韩先生"));
        TransitionNode pt4 = new TransitionNode(pnode, workTask);
        SubProcess ps4 = new SubProcess(wf).source(pnode).target(workTask).action(pt4);

        ParallelProcess pp = new ParallelProcess(wf).source(pnode);
        List<Process> processList = Lists.newArrayList( ps2, ps3, ps4);
        pp.setProcesses(processList);

        JoinNode joinNode = new JoinNode("合并");
        TransitionNode jt1 = new TransitionNode(resourceTask, joinNode);
        SubProcess js1 = new SubProcess(wf).source(resourceTask).target(joinNode).action(jt1);

        TransitionNode jt2 = new TransitionNode(financeTask, joinNode);
        SubProcess js2 = new SubProcess(wf).source(financeTask).target(joinNode).action(jt2);

        TransitionNode jt3 = new TransitionNode(workTask, joinNode);
        SubProcess js3 = new SubProcess(wf).source(workTask).target(joinNode).action(jt3);


        TaskNode auditTask = new TaskNode("总经理审批");
        auditTask.withEntrusts(Lists.newArrayList("刘总"));
        TransitionNode auditTrans = new TransitionNode(joinNode, auditTask);
        SubProcess js4 = new SubProcess(wf).source(joinNode).target(auditTask).action(auditTrans);
        JoinProcess jp = new JoinProcess(wf);
        jp.setTargetProcess(js4);
        List<SubProcess> joinSubProcess = Lists.newArrayList(js1, js2, js3);
        jp.setProcesses(joinSubProcess);


        EndNode end = new EndNode("结束");
        TransitionNode endTrans = new TransitionNode(auditTask, end);
        SubProcess endProcess = new SubProcess(wf).source(auditTask).target(end).action(endTrans);

        List<Process> allProcess = Lists.newArrayList();
        allProcess.add(s1);
        allProcess.add(s2);
        allProcess.add(pp);
        allProcess.add(jp);
        allProcess.add(endProcess);

        wf.setProcesses(allProcess);

//        JWorkFlow jWorkFlow  = wf.serialize();
//        String processJson = JSONArray.toJSONString(jWorkFlow.getProcesses());
//        String nodeMapJson = JSONObject.toJSONString(jWorkFlow.getNodeMap());
//        System.out.println("==========================process string is:" + processJson);
//
//        System.out.println("==========================nodeMap string is:" + nodeMapJson);
//        Map<String, BaseNode> nodeMap = wf.deserialMap(nodeMapJson);
//        List<Process> process = wf.deserialize(nodeMap, processJson);
//        wf.setProcesses(process);
//        System.out.println("======process:");
//        String ss = JSONArray.toJSONString(allProcess, SerializerFeature.DisableCircularReferenceDetect);
//        System.out.println(ss);
//
//        WorkFlowEngine engine = new WorkFlowEngine();
//        List<Process> deprocess = new WorkFlowTransfer(wf).processDeserialize(ss);//engine.processDeserialize(ss, wf);
//
//        System.out.println("======de  process:");
//        String dess = JSONArray.toJSONString(deprocess, SerializerFeature.DisableCircularReferenceDetect);
//        System.out.println(dess);
//        wf.setProcesses(deprocess);
//
//        List<Process> serProcess = JSONArray.parseArray(ss, Process.class);
//
//        System.out.println("");

        wf.setStart(start).setEnd(end);

//        wf.printCurrent();

        wf.doStart(Execution.createByNode(start).setActor("ning"));
        wf.printCurrent();
        Map<String, Execution> map1 = new HashMap<>();
        map1.put("辞职", Execution.createByNode(task).setActor("ning"));
        wf.doExecute(map1);
        wf.printCurrent();

        map1.put("辞职", Execution.createByNode(task).setActor("wang"));
        wf.doExecute(map1);
        wf.printCurrent();

        map1.put("辞职", Execution.createByNode(task).setActor("zhang"));
        wf.doExecute(map1);
        wf.printCurrent();
//
//        JWorkFlow jWorkFlow1  = wf.serialize();
//        String processJson1 = JSONArray.toJSONString(jWorkFlow1.getProcesses());
//        String nodeMapJson1 = JSONObject.toJSONString(jWorkFlow1.getNodeMap());
//        System.out.println("==========================process string is:" + processJson1);
//
//        System.out.println("==========================nodeMap string is:" + nodeMapJson1);
//
////
////
//
        Map<String, Execution> map3 = new HashMap<>();
        map3.put("人力交接", Execution.createByNode(resourceTask).setActor("哈女士"));
        map3.put("财务交接", Execution.createByNode(financeTask).setActor("王女士"));
        map3.put("工作交接", Execution.createByNode(workTask).setActor("韩先生"));
        wf.doExecute(map3);
        wf.printCurrent();
//
//
//        JWorkFlow jWorkFlow2  = wf.serialize();
//        String processJson2 = JSONArray.toJSONString(jWorkFlow2.getProcesses());
//        String nodeMapJson2 = JSONObject.toJSONString(jWorkFlow2.getNodeMap());
//        System.out.println("==========================process string is:" + processJson2);
//
//        System.out.println("==========================nodeMap string is:" + nodeMapJson2);


////
////
        Map<String, Execution> map5 = new HashMap<>();
        map5.put("总经理审批", Execution.createByNode(auditTask).setActor("刘总"));
        wf.doExecute(map5);
        wf.printCurrent();
//
        wf.doExecuteReject(end.name, Execution.createByNode(end).setActor("ning"));
        wf.printCurrent();

        wf.doExecuteReject(auditTask.name, Execution.createByNode(auditTask).setActor("刘总"));
        wf.printCurrent();
        wf.doExecuteReject(workTask.name, Execution.createByNode(workTask).setActor("韩先生"));
        wf.printCurrent();

        Map<String, Execution> map6 = new HashMap<>();
        map6.put("人力交接", Execution.createByNode(resourceTask).setActor("哈女士"));
        map6.put("财务交接", Execution.createByNode(financeTask).setActor("王女士"));
//        map3.put("工作交接", Execution.createByNode(workTask).setActor("韩先生"));
        wf.doExecute(map6);
        wf.printCurrent();
//
        Map<String, Execution> map11 = new HashMap<>();
        map11.put("辞职", Execution.createByNode(task).setActor("ning"));
        wf.doExecute(map11);
        wf.printCurrent();
//
        map11.put("辞职", Execution.createByNode(task).setActor("wang"));
        wf.doExecute(map11);
        wf.printCurrent();

        map11.put("辞职", Execution.createByNode(task).setActor("zhang"));
        wf.doExecute(map11);
        wf.printCurrent();

        Map<String, Execution> map33 = new HashMap<>();
        map33.put("人力交接", Execution.createByNode(resourceTask).setActor("哈女士"));
        map33.put("财务交接", Execution.createByNode(financeTask).setActor("王女士"));
        map33.put("工作交接", Execution.createByNode(workTask).setActor("韩先生"));
        wf.doExecute(map33);
        wf.printCurrent();

        System.out.println("====================================");

        wf.printTracks();
        wf.printExecutedTasks();




    }
    //辞职流程

//    public static void main(String[] args) {
//        WorkFlow wf = new WorkFlow();
//        StartNode start = new StartNode("start");
//        TaskNode task = new TaskNode("辞职");
//        task.setActionType(ActionTypeEnum.All).withEntrusts(Lists.newArrayList("ning","wang","zhang"));
//        TransitionNode t1 = new TransitionNode(start, task);
//
//        SubProcess s1 = new SubProcess(wf).source(start).target(task).action(t1);
//
//
//
//        ParallelNode pnode = new ParallelNode("并发");
//
//        JoinNode tempJoin = new JoinNode("合并—" + task.getName());
//        List<SubProcess> joinTaskProcess = Lists.newArrayList();
//        for (String s : task.getUserEntrusts()) {
//            TransitionNode t = new TransitionNode(task, tempJoin, false, false);
//            SubProcess sub = new SubProcess(wf).source(task).actor(s).target(tempJoin).action(t);
//            joinTaskProcess.add(sub);
//        }
//        TaskJoinProcess taskJoinProcess = new TaskJoinProcess(wf);
//        taskJoinProcess.setProcesses(joinTaskProcess);
//         task.setChildProcess(taskJoinProcess);
//
//        TransitionNode t2 = new TransitionNode(task, pnode);
//        SubProcess s2 = new SubProcess(wf).source(task).target(pnode).action(t2);
//
//
//        TaskNode resourceTask = new TaskNode("人力交接");
//        resourceTask.withEntrusts(Lists.newArrayList("哈女士"));
//        TransitionNode pt2 = new TransitionNode(pnode, resourceTask);
//        SubProcess ps2 = new SubProcess(wf).source(pnode).target(resourceTask).action(pt2);
//
//
//        TaskNode financeTask = new TaskNode("财务交接");
//        financeTask.withEntrusts(Lists.newArrayList("王女士"));
//        TransitionNode pt3 = new TransitionNode(pnode, financeTask);
//        SubProcess ps3 = new SubProcess(wf).source(pnode).target(financeTask).action(pt3);
//
//        TaskNode workTask = new TaskNode("工作交接");
//        workTask.withEntrusts(Lists.newArrayList("韩先生"));
//        TransitionNode pt4 = new TransitionNode(pnode, workTask);
//        SubProcess ps4 = new SubProcess(wf).source(pnode).target(workTask).action(pt4);
//
//        ParallelProcess pp = new ParallelProcess(wf).source(pnode);
//        List<Process> processList = Lists.newArrayList( ps2, ps3, ps4);
//        pp.setProcesses(processList);
//
//        JoinNode joinNode = new JoinNode("合并");
//        TransitionNode jt1 = new TransitionNode(resourceTask, joinNode);
//        SubProcess js1 = new SubProcess(wf).source(resourceTask).target(joinNode).action(jt1);
//
//        TransitionNode jt2 = new TransitionNode(financeTask, joinNode);
//        SubProcess js2 = new SubProcess(wf).source(financeTask).target(joinNode).action(jt2);
//
//        TransitionNode jt3 = new TransitionNode(workTask, joinNode);
//        SubProcess js3 = new SubProcess(wf).source(workTask).target(joinNode).action(jt3);
//
//
//        TaskNode auditTask = new TaskNode("总经理审批");
//        auditTask.withEntrusts(Lists.newArrayList("刘总"));
//        TransitionNode auditTrans = new TransitionNode(joinNode, auditTask);
//        JoinProcess jp = new JoinProcess(wf);
//        jp.action(auditTrans).target(auditTask);
//        List<SubProcess> joinSubProcess = Lists.newArrayList(js1, js2, js3);
//        jp.setProcesses(joinSubProcess);
//
//
//        EndNode end = new EndNode("结束");
//        TransitionNode endTrans = new TransitionNode(auditTask, end);
//        SubProcess endProcess = new SubProcess(wf).source(auditTask).target(end).action(endTrans);
//
//        List<Process> allProcess = Lists.newArrayList();
//        allProcess.add(s1);
//        allProcess.add(s2);
//        allProcess.add(pp);
//        allProcess.add(jp);
//        allProcess.add(endProcess);
//
//        wf.setProcesses(allProcess);
//        wf.setStart(start);
//
//        wf.printCurrent();
//
//        wf.doStart(Execution.createByNode(start).setActor("ning"));
//        wf.printCurrent();
//        Map<String, Execution> map1 = new HashMap<>();
//        map1.put("辞职", Execution.createByNode(task).setActor("ning"));
//        wf.doExecute(map1);
//        wf.printCurrent();
//
//        map1.put("辞职", Execution.createByNode(task).setActor("wang"));
//        wf.doExecute(map1);
//        wf.printCurrent();
//
//        map1.put("辞职", Execution.createByNode(task).setActor("zhang"));
//        wf.doExecute(map1);
//        wf.printCurrent();
//
//
//        Map<String, Execution> map2 = new HashMap<>();
//        map2.put("并发", Execution.createByNode(pnode).setActor("ning"));
//        wf.doExecute(map2);
//        wf.printCurrent();
//
//
//        Map<String, Execution> map3 = new HashMap<>();
//        map3.put("人力交接", Execution.createByNode(resourceTask).setActor("哈女士"));
//        map3.put("财务交接", Execution.createByNode(financeTask).setActor("王女士"));
//        map3.put("工作交接", Execution.createByNode(workTask).setActor("韩先生"));
//        wf.doExecute(map3);
//        wf.printCurrent();
//
//        Map<String, Execution> map4 = new HashMap<>();
//        map4.put("合并", Execution.createByNode(joinNode).setActor("ning"));
//        wf.doExecute(map4);
//        wf.printCurrent();
//
//        Map<String, Execution> map5 = new HashMap<>();
//        map5.put("总经理审批", Execution.createByNode(auditTask).setActor("刘总"));
//        wf.doExecute(map5);
//        wf.printCurrent();
//
//
//
//
//
//
//
//
//
//
//
//    }
}
